`define WB_IDLE 2'b00
`define WB_BUSY 2'b01
`define WB_WAIT_FOR_FLUSHING 2'b10
`define WB_WAIT_FOR_STALL 2'b11

module wishbone_bus_if(

	input	wire										clk,
	input wire										rst,
	
	//??????ctrl
	input                         stall_i,
	input                         flush_i,
	
	//CPU???????
	input wire                    cpu_ce_i,
	input wire[31:0]           cpu_data_i,
	input wire[31:0]           cpu_addr_i,
	input wire                    cpu_we_i,
	input wire[3:0]               cpu_sel_i,
	output reg[31:0]           cpu_data_o,
	
	//Wishbone?????
	input wire[31:0]           wishbone_data_i,
	input wire                    wishbone_ack_i,
	output reg[31:0]           wishbone_addr_o,
	output reg[31:0]           wishbone_data_o,
	output reg                    wishbone_we_o,
	output reg[3:0]               wishbone_sel_o,
	output reg                    wishbone_stb_o,
	output reg                    wishbone_cyc_o,

	output reg                    stallreq	       
	
);

  reg[1:0] wishbone_state;
  reg[31:0] rd_buf;

	always @ (posedge clk) begin
		if(rst == 1'b1) begin
			wishbone_state <= `WB_IDLE;
			wishbone_addr_o <= 32'h00000000;
			wishbone_data_o <= 32'h00000000;
			wishbone_we_o <= 1'b0;
			wishbone_sel_o <= 4'b0000;
			wishbone_stb_o <= 1'b0;
			wishbone_cyc_o <= 1'b0;
			rd_buf <= 32'h00000000;
//			cpu_data_o <= 32'h00000000;
		end else begin
			case (wishbone_state)
				`WB_IDLE:		begin
					if((cpu_ce_i == 1'b1) && (flush_i == 1'b0)) begin
						wishbone_stb_o <= 1'b1;
						wishbone_cyc_o <= 1'b1;
						wishbone_addr_o <= cpu_addr_i;
						wishbone_data_o <= cpu_data_i;
						wishbone_we_o <= cpu_we_i;
						wishbone_sel_o <=  cpu_sel_i;
						wishbone_state <= `WB_BUSY;
						rd_buf <= 32'h00000000;
//					end else begin
//						wishbone_state <= WB_IDLE;
//						wishbone_addr_o <= 32'h00000000;
//						wishbone_data_o <= 32'h00000000;
//						wishbone_we_o <= 1'b0;
//						wishbone_sel_o <= 4'b0000;
//						wishbone_stb_o <= 1'b0;
//						wishbone_cyc_o <= 1'b0;
//						cpu_data_o <= 32'h00000000;			
					end							
				end
				`WB_BUSY:		begin
					if(wishbone_ack_i == 1'b1) begin
						wishbone_stb_o <= 1'b0;
						wishbone_cyc_o <= 1'b0;
						wishbone_addr_o <= 32'h00000000;
						wishbone_data_o <= 32'h00000000;
						wishbone_we_o <= 1'b0;
						wishbone_sel_o <=  4'b0000;
						wishbone_state <= `WB_IDLE;
						if(cpu_we_i == 1'b0) begin
							rd_buf <= wishbone_data_i;
						end
						
						if(stall_i != 1'b0) begin
							wishbone_state <= `WB_WAIT_FOR_STALL;
						end					
					end else if(flush_i == 1'b1) begin
					  wishbone_stb_o <= 1'b0;
						wishbone_cyc_o <= 1'b0;
						wishbone_addr_o <= 32'h00000000;
						wishbone_data_o <= 32'h00000000;
						wishbone_we_o <= 1'b0;
						wishbone_sel_o <=  4'b0000;
						wishbone_state <= `WB_IDLE;
						rd_buf <= 32'h00000000;
					end
				end
				`WB_WAIT_FOR_STALL:		begin
					if(stall_i == 1'b0) begin
						wishbone_state <= `WB_IDLE;
					end
				end
				default: begin
				end 
			endcase
		end    //if
	end      //always
			

	always @ (*) begin
		if(rst == 1'b1) begin
			stallreq <= 1'b0;
			cpu_data_o <= 32'h00000000;
		end else begin
			stallreq <= 1'b0;
			case (wishbone_state)
				`WB_IDLE:		begin
					if((cpu_ce_i == 1'b1) && (flush_i == 1'b0)) begin
						stallreq <= 1'b1;
						cpu_data_o <= 32'h00000000;				
					end
				end
				`WB_BUSY:		begin
					if(wishbone_ack_i == 1'b1) begin
						stallreq <= 1'b0;
						if(wishbone_we_o == 1'b0) begin
							cpu_data_o <= wishbone_data_i;  //????
						end else begin
						  cpu_data_o <= 32'h00000000;
						end							
					end else begin
						stallreq <= 1'b1;	
						cpu_data_o <= 32'h00000000;				
					end
				end
				`WB_WAIT_FOR_STALL:		begin
					stallreq <= 1'b0;
					cpu_data_o <= rd_buf;
				end
				default: begin
				end 
			endcase
		end    //if
	end      //always

endmodule